package com.trade.data.job;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import cn.hutool.poi.excel.ExcelReader;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.trade.data.dao.entity.PredictInfo;
import com.trade.data.dao.service.PredictInfoService;
import com.trade.data.dto.CoinMarketDto;
import com.trade.data.dto.CoinQuoteDto;
import com.trade.data.dto.PredictInfoDto;
import com.trade.data.manager.CoinMarketManager;
import com.trade.data.model.ModelEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.Lists;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.*;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;


@Component
@Slf4j
public class ExcelJob {

    @Autowired
    CoinMarketManager coinMarketManager;
    @Autowired
    PredictInfoService predictInfoService;

    @Scheduled(cron = "5 0,5,10,15,20,25,30,35,40,45,50,55 * * * ?")
    public void executeProduceExcelTask5m() {

        String symbol = "1000SATSUSDT";
        String interval = "5m";
        log.info("executeProduceExcelTask   coin:{} interval:{}",symbol,interval);
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        produceExcelKindle(symbol,interval);
        stopWatch.stop();
        log.info("single exec  executeProduceExcelTask   coin:{} interval:{} stopWatch cost : {} ms  amount", symbol,interval,stopWatch.getTotalTimeMillis());
    }
    @Scheduled(cron = "10 0,5,10,15,20,25,30,35,40,45,50,55 * * * ?")
    public void executeSendExcelTask5m() throws FileNotFoundException {

        String symbol = "1000SATSUSDT";
        String interval = "5m";
        log.info("get python result  symbol :{} interval :{}",symbol,interval);
        SendExcelTask(symbol,interval,ModelEnum.random_forest);
        SendExcelTask(symbol,interval,ModelEnum.random_forest_v1);
    }


    @Scheduled(cron = "5 0,15,30,45 * * * ?")
    public void executeProduceExcelTask15m() {

        String symbol = "1000SATSUSDT";
        String interval = "15m";
        log.info("executeProduceExcelTask   coin:{} interval:{}",symbol,interval);
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        produceExcelKindle(symbol,interval);
        stopWatch.stop();
        log.info("single exec  executeProduceExcelTask   coin:{} interval:{} stopWatch cost : {} ms  amount", symbol,interval,stopWatch.getTotalTimeMillis());
    }
    @Scheduled(cron = "15 0,15,30,45 * * * ?")
    public void executeSendExcelTask15m() throws FileNotFoundException {
        String symbol = "1000SATSUSDT";
        String interval = "15m";
        log.info("get python result  symbol :{} interval :{}",symbol,interval);
        SendExcelTask(symbol,interval,ModelEnum.random_forest);
        SendExcelTask(symbol,interval,ModelEnum.random_forest_v1);
    }

    @Scheduled(cron = "5 0,30 * * * ?")
    public void executeProduceExcelTask30m() {

        String symbol = "1000SATSUSDT";
        String interval = "30m";
        log.info("executeProduceExcelTask   coin:{} interval:{}",symbol,interval);
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        produceExcelKindle(symbol,interval);
        stopWatch.stop();
        log.info("single exec  executeProduceExcelTask   coin:{} interval:{} stopWatch cost : {} ms  amount", symbol,interval,stopWatch.getTotalTimeMillis());
    }
    @Scheduled(cron = "15 0,30 * * * ?")
    public void executeSendExcelTask30m() throws FileNotFoundException {
        String symbol = "1000SATSUSDT";
        String interval = "30m";
        log.info("get python result  symbol :{} interval :{}",symbol,interval);
        SendExcelTask(symbol,interval,ModelEnum.random_forest);
        SendExcelTask(symbol,interval,ModelEnum.random_forest_v1);
    }

    @Scheduled(cron = "6 0 * * * ?")
    public void executeProduceExcelTask1h() {

        String symbol = "1000SATSUSDT";
        String interval = "1h";
        log.info("executeProduceExcelTask   coin:{} interval:{}",symbol,interval);
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        produceExcelKindle(symbol,interval);
        stopWatch.stop();
        log.info("single exec  executeProduceExcelTask   coin:{} interval:{} stopWatch cost : {} ms  amount", symbol,interval,stopWatch.getTotalTimeMillis());
    }
    @Scheduled(cron = "14 0 * * * ?")
    public void executeSendExcelTask1h() throws FileNotFoundException {
        String symbol = "1000SATSUSDT";
        String interval = "1h";
        log.info("get python result  symbol :{} interval :{}",symbol,interval);
        SendExcelTask(symbol,interval,ModelEnum.random_forest);
        SendExcelTask(symbol,interval,ModelEnum.random_forest_v1);
    }

    @Scheduled(cron = "8 0 8 * * ?")
    public void executeProduceExcelTask24h() {
        String symbol = "1000SATSUSDT";
        String interval = "1d";
        log.info("executeProduceExcelTask   coin:{} interval:{}",symbol,interval);
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        produceExcelKindle(symbol,interval);
        stopWatch.stop();
        log.info("single exec  executeProduceExcelTask   coin:{} interval:{} stopWatch cost : {} ms  amount", symbol,interval,stopWatch.getTotalTimeMillis());
    }
    @Scheduled(cron = "18 0 8 * * ?")
    public void executeSendExcelTask24() throws FileNotFoundException {
        String symbol = "1000SATSUSDT";
        String interval = "1d";
        log.info("get python result  symbol :{} interval :{}",symbol,interval);
        SendExcelTask(symbol,interval,ModelEnum.random_forest);
        SendExcelTask(symbol,interval,ModelEnum.random_forest_v1);
    }
    @Scheduled(cron = "8 0 8 ? * MON")
    public void executeProduceExcelTask1weeek() {
        String symbol = "1000SATSUSDT";
        String interval = "1w";
        log.info("executeProduceExcelTask   coin:{} interval:{}",symbol,interval);
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();
        produceExcelKindle(symbol,interval);
        stopWatch.stop();
        log.info("single exec  executeProduceExcelTask   coin:{} interval:{} stopWatch cost : {} ms  amount", symbol,interval,stopWatch.getTotalTimeMillis());
    }
    @Scheduled(cron = "16 0 8 ? * MON")
    public void executeSendExcelTask1weeek() throws FileNotFoundException {
        String symbol = "1000SATSUSDT";
        String interval = "1w";
        log.info("get python result  symbol :{} interval :{}",symbol,interval);
        SendExcelTask(symbol,interval,ModelEnum.random_forest);
        SendExcelTask(symbol,interval,ModelEnum.random_forest_v1);
    }
    public void SendExcelTask(String symbol, String interval, ModelEnum modelEnum) throws FileNotFoundException {
        StopWatch stopWatch = new StopWatch();
        stopWatch.start();

        // 遍历每个 CSV 文件并发送到 Flask 服务器
        String flaskUrl = "http://127.0.0.1:5000/upload";  // 替换为你的 Flask 服务器 URL
        HttpRequest request = HttpUtil.createPost(flaskUrl);
        Optional<File> file = Optional.ofNullable(readFile(symbol, interval));
        File filenew = null;

        if (file.isPresent()) {
            log.info("读取文件成功");
            filenew = file.get();

            // 读取 CSV 文件最后一行数据
            List<String> lastRowList = readLastCsvRow(filenew);

            // 处理文件并发送到 Flask 服务器
            request.form("file", filenew);
            request.form("model_name",modelEnum.name());
            HttpResponse response = request.execute();

            if(response.isOk()){
                int status = response.getStatus();
                // 存入数据库信息
                PredictInfoDto predictInfoDto = new PredictInfoDto();
                predictInfoDto.setPredictCreateat(new Date());
                predictInfoDto.setCurrencyName(symbol);
                predictInfoDto.setCurrentClosePrice(!CollectionUtils.isEmpty(lastRowList) ? new BigDecimal(lastRowList.get(5)) : new BigDecimal("0"));
                predictInfoDto.setPredictBatchNum(IdUtil.getSnowflakeNextIdStr());
                predictInfoDto.setPredictUniqueTag(!CollectionUtils.isEmpty(lastRowList) ? lastRowList.get(0) : "0");
                predictInfoDto.setPeriodDimension(interval);
                predictInfoDto.setResultCode(String.valueOf(status));

                if(200 == status){
                    PredictInfoDto bean = JSONUtil.toBean(response.body(), PredictInfoDto.class);
                    predictInfoDto.setPredictCloseprice(bean.getPredictCloseprice());
                    predictInfoDto.setPredictClosetime(bean.getPredictClosetime());
                    predictInfoDto.setPredictResult(bean.getPredictResult());
                    predictInfoDto.setModelName(bean.getModelName());
                } else {
                    predictInfoDto.setPredictResult("error");
                }

                PredictInfo predictInfo = new PredictInfo();
                BeanUtils.copyProperties(predictInfoDto, predictInfo);
                predictInfoService.save(predictInfo);

                log.info("预测结果：{}", response.body());
            }
        }

        stopWatch.stop();
        log.info("single exec stopWatch cost : {} ms", stopWatch.getTotalTimeMillis());
    }

    private List<String> readLastCsvRow(File file) {
        List<String> lastRow = new ArrayList<>();
        try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
            String line;
            while ((line = reader.readLine()) != null) {
                String[] values = line.split(",");
                lastRow = Arrays.asList(values);  // 每次更新为最新的行
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return lastRow;
    }
    
    public File readFile(String symbol, String interval) throws FileNotFoundException {
        String projectRoot = System.getProperty("user.dir");
        String fileName = symbol.toLowerCase() + "_" + interval + ".csv";
        String relativeDirectory = "csv/file";

        // 获取项目根路径的上一层目录
        Path parentOfProjectRoot = Paths.get(projectRoot).getParent();
        if (parentOfProjectRoot == null) {
            System.err.println("Parent directory of project root could not be determined.");
            return null;
        }

        // 构建目标目录路径
        Path directoryPath = parentOfProjectRoot.resolve(relativeDirectory);

        // 如果目录不存在，创建目录
        try {
            if (Files.notExists(directoryPath)) {
                Files.createDirectories(directoryPath);
                System.out.println("Directory created: " + directoryPath.toString());
            } else {
                System.out.println("Directory already exists: " + directoryPath.toString());
            }
        } catch (IOException e) {
            System.err.println("Failed to create directory: " + directoryPath.toString());
            e.printStackTrace();
            return null;
        }

        // 构建文件路径
        Path filePath = directoryPath.resolve(fileName);
        File file = filePath.toFile();
        // 如果文件不存在，创建文件；如果文件存在，更新文件
        if (Files.notExists(filePath)) {
            return null;
        }
        return file;  // 返回文件对象
    }

    public void  produceExcelKindle(String symbol, String interval){
        List<List> binanceQuotes = coinMarketManager.getBinanceQuotes(symbol, interval);
        if (CollectionUtils.isEmpty(binanceQuotes)) {
            return;
        }

        CoinMarketDto coinMarketDto = new CoinMarketDto();
        coinMarketDto.setInterval(interval);
        coinMarketDto.setSymbol(symbol);

        List<CoinQuoteDto> coinQuoteDtos = coinMarketManager.transantObject(coinMarketDto, binanceQuotes);

        String projectRoot = System.getProperty("user.dir");
        String fileName = coinMarketDto.getSymbol().toLowerCase() + "_" + coinMarketDto.getInterval() + ".csv";
        String relativeDirectory = "csv/file";

        // 获取项目根路径的上一层目录
        Path parentOfProjectRoot = Paths.get(projectRoot).getParent();
        if (parentOfProjectRoot == null) {
            System.err.println("Parent directory of project root could not be determined.");
            return;
        }

        // 构建目标目录路径
        Path directoryPath = parentOfProjectRoot.resolve(relativeDirectory);

        // 如果目录不存在，创建目录
        try {
            if (Files.notExists(directoryPath)) {
                Files.createDirectories(directoryPath);
                System.out.println("Directory created: " + directoryPath.toString());
            } else {
                System.out.println("Directory already exists: " + directoryPath.toString());
            }
        } catch (IOException e) {
            System.err.println("Failed to create directory: " + directoryPath.toString());
            e.printStackTrace();
            return;
        }

        // 构建文件路径
        Path filePath = directoryPath.resolve(fileName);
        File file = filePath.toFile();

        // 用 Map 来存储去重后的数据，key 为序号
        Map<String, List<Object>> dataMap = new LinkedHashMap<>();

        // 如果文件存在，读取文件并存储到 dataMap
        if (file.exists()) {
            try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
                String line;
                boolean isFirstLine = true; // 跳过表头
                while ((line = reader.readLine()) != null) {
                    if (isFirstLine) {
                        isFirstLine = false;
                        continue;
                    }
                    String[] values = line.split(",");
                    String id = values[0]; // 序号为第一列
                    dataMap.put(id, Arrays.asList(values));
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        // 将新的数据合并到 dataMap 中（按序号去重）
        for (CoinQuoteDto dto : coinQuoteDtos) {
            String id = dto.getId();
            List<Object> newRow = CollUtil.newArrayList(
                    id,
                    DateUtil.formatDateTime(dto.getTradeDate()),
                    dto.getOpeningPrice(),
                    dto.getHighestPrice(),
                    dto.getLowestPrice(),
                    dto.getClosingPrice(),
                    dto.getVolume(),
                    DateUtil.formatDateTime(dto.getClosingTime()),
                    dto.getTurnover(),
                    dto.getTransactionCount(),
                    dto.getActiveBuyVolume(),
                    dto.getActiveBuyTurnover()
            );
            dataMap.put(id, newRow); // 如果 id 存在，则覆盖旧数据
        }

        // 将 dataMap 转为 List，按照序号进行排序
        List<List<Object>> finalRows = new ArrayList<>(dataMap.values());

     // 对 finalRows 进行按 "开盘时间" 列排序
        finalRows.sort((row1, row2) -> {
            String tradeDate1 = row1.get(1).toString();
            String tradeDate2 = row2.get(1).toString();
            return tradeDate1.compareTo(tradeDate2);  // 升序排序
        });

        // 移除最后一行未完全定数据
        if (!finalRows.isEmpty()) {
            finalRows.remove(finalRows.size() - 1);
        }
        // 写入 CSV 文件
        try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) {
            // 写入表头
            writer.write("序号,开盘时间,开盘价,最高价,最低价,收盘价,交易量,收盘时间,成交额,成交笔数,主动买入成交量,主动买入成交额");
            writer.newLine();

            // 写入数据
            for (List<Object> row : finalRows) {
                writer.write(String.join(",", rowToStringArray(row)));
                writer.newLine();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }

        log.info("Saved CSV with {} rows at: {}", finalRows.size(), filePath);
    }


    // 将 List<Object> 转为字符串数组，用于 CSV 写入
    private String[] rowToStringArray(List<Object> row) {
        return row.stream().map(Object::toString).toArray(String[]::new);
    }
    // 辅助方法：将 List<Object> 转换为 Map<String, Object>
    private Map<String, Object> convertListToMap(List<Object> list) {
        Map<String, Object> map = new LinkedHashMap<>();
        map.put("序号", list.get(0));
        map.put("开盘时间", list.get(1));
        map.put("开盘价", list.get(2));
        map.put("最高价", list.get(3));
        map.put("最低价", list.get(4));
        map.put("收盘价", list.get(5));
        map.put("交易量", list.get(6));
        map.put("收盘时间", list.get(7));
        map.put("成交额", list.get(8));
        map.put("成交笔数", list.get(9));
        map.put("主动买入成交量", list.get(10));
        map.put("主动买入成交额", list.get(11));
        return map;
    }

}
